import Config  from '@/assets/js/config.js'
import Utils from '@/uni_modules/yingbing-ui/js_sdk/util.js'
import request from '@/uni_modules/yingbing-request/js_sdk'
import gb2312 from '@/assets/other/gb2312.js'
import cryptoJS from "@/assets/crypto-js/crypto-js.js"
import base64 from "@/assets/other/base64.js"
import htmlParser from "@/uni_modules/html-parser/js_sdk/index.js"
import Dict from '@/assets/other/dict.js'
import Trie from '@/assets/other/trie.js';
import { simpleToTraditional, traditionalToSimple } from '@/assets/other/s2t.js';

const { ERR_OK, ERR_FALSE } = Config
const { dateFormat, time2seconds, convertUrlQueryObject, uncode, zeroize } = Utils

let dict = Dict
let str = simpleToTraditional(dict.toString())
str = str + ',' + traditionalToSimple(str)
str = str + ',' + str.toUpperCase()
str = str + ',' + str.toLowerCase()
dict = dict.concat(str.split(','))
const trie = new Trie()
trie.init([...new Set(dict)])

const HTMLParser = htmlParser
const Base64 = base64
const CryptoJS = cryptoJS
const Xhr = request.xhr
const Http = request.http
const GBK = gb2312
const HtmlDecode = htmlDecode
const DecodeUnicode = uncode
const DateFormat = dateFormat
const TimeToseconds = time2seconds
const Zeroize = zeroize
const ConvertUrlQueryObject = convertUrlQueryObject
export const statement = ['@sync:', '@async:', '@sel:', '@json:', '@for:', '@map:', '@filter:', '@find:', '@sort:', '@replace:', '@replaceAll:', '@split:', '@string:', '@dateFormat:', '@join:', '@trim:','@have:', '@equal:', '@unequal:', '@eval:', '@match:', '@reverse:', '@relation:', '@type:', '@method:', '@header:', '@params:']//声明符
let lastDetailData, lastDetailUrl
export default async function (name, url, req, query = {}) {
	if ( !name || !url || !req || !query ) return { code: ERR_FALSE, data: null }
	const resultsFormat = async function (res, req) {
		try{
			response = typeof res.data == 'string' ? htmlDecode(res.data) : res.data
			let list = [], data = {}, nextUrl = ''
			const rules = Object.keys(req).filter(key => key != 'source' && key != 'reqId' && key != 'type' && key != 'ua' && key != 'url' && key != 'list' && key != 'nextUrl' && key != 'response' && req[key])
			if ( req.list ) {
				const lastReuslts = await valueFormat(response, req.list)
				if ( req.nextUrl ) {
					const pre = req.nextUrl.indexOf(':') > -1 ? req.nextUrl.slice(0, req.nextUrl.indexOf(':')+1) : ''
					nextUrl = statement.indexOf(pre) == -1 ? await textFormat(response, req.nextUrl) : await valueFormat(response, req.nextUrl)
				}
				for ( let i=0;i<lastReuslts.length;i++ ) {
					const lastReuslt = lastReuslts[i]
					const rulesPromise = rules.map(key => {
						const pre = req[key].indexOf(':') > -1 ? req[key].slice(0, req[key].indexOf(':')+1) : ''
						return statement.indexOf(pre) == -1 ? textFormat(lastReuslt, req[key]) : valueFormat(lastReuslt, req[key])
					})
					const ress = await Promise.all(rulesPromise)
					const rus = {}
					ress.forEach((result, key) => {
						if ( rules[key] != 'nextUrl' ) {
							rus[rules[key]] = result
						} else {
							nextUrl = result
						}
					})
					list.push(Object.assign({}, rus, {
						id: rus.id || encodeURIComponent((rus.detailUrl || rus.contextUrl || rus.src || i) + '_' + (requestName == 'character' ? 'character' : type) + '_' + req.source.id),
						type: requestName == 'character' ? 'character' : type,
						isAdult: req.source.isAdult,
						source: req.source.id
					}))
				}
				const result ={ nextUrl, isLastPage: list.length == 0, list }
				network.result = result
				return { code: ERR_OK, data: result, network }
			} else {
				if ( req.response ) {
					const pre = req.response.indexOf(':') > -1 ? req.response.slice(0, req.response.indexOf(':')+1) : ''
					response = statement.indexOf(pre) == -1 ? await textFormat(response, req.response) : await valueFormat(response, req.response)
				}
				if ( req.nextUrl ) {
					const pre = req.nextUrl.indexOf(':') > -1 ? req.nextUrl.slice(0, req.nextUrl.indexOf(':')+1) : ''
					nextUrl = statement.indexOf(pre) == -1 ? await textFormat(response, req.nextUrl) : await valueFormat(response, req.nextUrl)
				}
				const rulesPromise = rules.map(key => {
					const pre = req[key].indexOf(':') > -1 ? req[key].slice(0, req[key].indexOf(':')+1) : ''
					return statement.indexOf(pre) == -1 ? textFormat(response, req[key]) : valueFormat(response, req[key])
				})
				const ress = await Promise.all(rulesPromise)
				ress.forEach((result, key) => data[rules[key]] = result)
				if ( requestName == 'detail' ) {
					data.shareUrl = data.shareUrl || requestUrl
					data.tag = getTag(data)
				}
				const result = { data, nextUrl }
				network.result = result
				return { code: ERR_OK, data: result, network }
			}
		}catch(e){
			throwerror('resultsFormat', e)
			network.result = null
			return { code: ERR_FALSE, data: null, network }
		}
	}
	
	const extractPatternData = function (inputString, patterns) {
		try{
			return extractPattern(inputString, patterns)
		}catch(e){
			throwerror(inputString, e)
			return null
		}
	}
	
	const urlFormat = async function (urlRule) {
		try{
			const pre = urlRule.indexOf(':') > -1 ? urlRule.slice(0, urlRule.indexOf(':')+1) : ''
			let result = '', type = '', method = '', header = {}, params = {}
			const regex = new RegExp(`(${statement.join('|')}|$)`)
			if ( statement.indexOf(pre) == -1 ) result = urlRule.split(regex)[0]
			const arr = extractPatternData(urlRule, statement)
			for ( let i = 0; i < arr.length; i++ ) {
				const rule = escapeFormat(arr[i].data)
				const pre = arr[i].type
				if ( pre == '@type:' ) { type = rule }
				else if ( pre == '@method:' ) { method = rule }
				else if ( pre == '@header:' ) {
					let value = rule
					const binds = value.match(/{{[^}}]+}}/g) || []
					binds.forEach(bind => {
						const handle = bind.match(/{{*([\s\S]*?)}}/)[1]
						value = value.replace(bind, eval("( function () { return " + handle + "})")())
					})
					header = eval('( function () { return {' + value + '}})')()
				} else if ( pre == '@params:' ) {
					let value = rule
					const binds = value.match(/{{[^}}]+}}/g) || []
					binds.forEach(bind => {
						const handle = bind.match(/{{*([\s\S]*?)}}/)[1]
						value = value.replace(bind, eval("( function () { return " + handle + "})")())
					})
					params = eval('( function () { return {' + value + '}})')()
				} else if ( pre == '@sync:' ) {
					result = syncFormat(result, rule)
				} else if ( pre == '@async:' ) {
					result = await asyncFormat(result, rule)
				} else if ( pre == '@json:' ) {
					result = jsonFormat(result, rule)
				} else if ( pre == '@sel:' ) {
					result = selFormat(result, rule)
				} else if ( pre == '@for:' ) {
					result = forFormat(result, rule)
				} else if ( pre == '@map:' ) {
					result = mapFormat(result, rule)
				} else if ( pre == '@filter:' ) {
					result = filterFormat(result, rule)
				} else if ( pre == '@replace:' ) {
					result = replaceFormat(result, rule)
				} else if ( pre == '@replaceAll:' ) {
					result = replaceAllFormat(result, rule)
				} else if ( pre == '@split:' ) {
					result = splitFormat(result, rule)
				} else if ( pre == '@find:' ) {
					result = findFormat(result, rule)
				} else if ( pre == '@sort:' ) {
					result = sortFormat(result, rule)
				} else if ( pre == '@trim:' ) {
					result = trimFormat(result, rule)
				} else if ( pre == '@have:' ) {
					result = haveFormat(result, rule)
				} else if ( pre == '@equal:' ) {
					result = equalFormat(result, rule)
				} else if ( pre == '@unequal:' ) {
					result = unequalFormat(result, rule)
				} else if ( pre == '@eval:' ) {
					result = evalFormat(result, rule)
				} else if ( pre == '@match:' ) {
					result = matchFormat(result, rule)
				} else if ( pre == '@string:' ) {
					result = stringFormat(result, rule)
				} else if ( pre == '@dateFormat:' ) {
					result = dateFormatFormat(result, rule)
				} else if ( pre == '@join:' ) {
					result = joinFormat(result, rule)
				} else if ( pre == '@reverse:' ) {
					result = reverseFormat(result, rule)
				}
				const log = JSON.stringify(result) || ''
				if ( network ) network.log += rule + '：' + log + '\n\n'
			}
			const requestConfig = typeof result == 'string' ? { url: result, type, method, header, params} : Object.assign({}, {type, method, header, params}, result)
			if ( requestConfig.url ) {
				const binds = requestConfig.url.match(/{{[^}}]+}}/g) || []
				binds.forEach(bind => {
					const handle = bind.match(/{{*([\s\S]*?)}}/)[1]
					requestConfig.url = requestConfig.url.replace(bind, eval("( function () { return " + handle + "})")())
				})
			}
			return requestConfig
		}catch(e){
			throwerror(urlRule, e)
			return {url: ''}
		}
	}
	
	const baseUrlFormat = async function (content, rule) {
		try{
			const pre = rule.indexOf(':') > -1 ? rule.slice(0, rule.indexOf(':')+1) : ''
			return statement.indexOf(pre) == -1 ? await textFormat(content, rule) : await valueFormat(content, rule)
		}catch(e){
			return ''
		}
	}
	
	const textFormat = async function (content, rule) {
		try{
			let text = rule.replace('@text:', '')
			let arr = text.match(/<js>*([\s\S]*?)<\/js>/g) || []
			for ( let i=0;i<arr.length;i++ ) {
				let value = arr[i].match(/<js>*([\s\S]*?)<\/js>/)[1]
				text = text.replace(arr[i], await valueFormat(content, value))
			}
			text = escapeFormat(text) || ''
			if ( network ) network.log += rule + '：' + text + '\n\n'
			return text
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const valueFormat = async function (content, rules) {
		let result = content
		const arr = extractPatternData(rules, statement)
		for ( let i = 0; i < arr.length; i++ ) {
			const rule = escapeFormat(arr[i].data)
			const pre = arr[i].type
			if ( pre == '@sync:' ) {
				result = syncFormat(result, rule)
			} else if ( pre == '@async:' ) {
				result = await asyncFormat(result, rule)
			} else if ( pre == '@json:' ) {
				result = jsonFormat(result, rule)
			} else if ( pre == '@sel:' ) {
				result = selFormat(result, rule)
			} else if ( pre == '@for:' ) {
				result = forFormat(result, rule)
			} else if ( pre == '@map:' ) {
				result = mapFormat(result, rule)
			} else if ( pre == '@filter:' ) {
				result = filterFormat(result, rule)
			} else if ( pre == '@replace:' ) {
				result = replaceFormat(result, rule)
			} else if ( pre == '@replaceAll:' ) {
				result = replaceAllFormat(result, rule)
			} else if ( pre == '@split:' ) {
				result = splitFormat(result, rule)
			} else if ( pre == '@find:' ) {
				result = findFormat(result, rule)
			} else if ( pre == '@sort:' ) {
				result = sortFormat(result, rule)
			} else if ( pre == '@trim:' ) {
				result = trimFormat(result, rule)
			} else if ( pre == '@have:' ) {
				result = haveFormat(result, rule)
			} else if ( pre == '@equal:' ) {
				result = equalFormat(result, rule)
			} else if ( pre == '@unequal:' ) {
				result = unequalFormat(result, rule)
			} else if ( pre == '@eval:' ) {
				result = evalFormat(result, rule)
			} else if ( pre == '@match:' ) {
				result = matchFormat(result, rule)
			} else if ( pre == '@string:' ) {
				result = stringFormat(result, rule)
			} else if ( pre == '@dateFormat:' ) {
				result = dateFormatFormat(result, rule)
			} else if ( pre == '@join:' ) {
				result = joinFormat(result, rule)
			} else if ( pre == '@reverse:' ) {
				result = reverseFormat(result, rule)
			} else {
				result = result + pre + rule
			}
			const log = JSON.stringify(result) || ''
			if ( network ) network.log += rule + '：' + log + '\n\n'
		}
		return result
	}
	
	const syncFormat = function (lastResult, rule) {
		try{
			let handle = eval(
				"( function () {" + rule + " } )"
			)
			return handle()
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const asyncFormat = async function (lastResult, rule) {
		try{
			let handle = eval(
				"( async function () {" + rule + "} )"
			)
			return await handle()
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const jsonFormat = function (lastResult, rule) {
		try{
			let result = lastResult
			const arr = rule.split('.')
			for ( let i = 0;i < arr.length;i++ ) {
				const downIndex = arr[i].match(/\[([^\]]+)\]/)
				const key = downIndex ? arr[i].replace(downIndex[0], '') : arr[i]
				result = key ? result[key] : result
				result = downIndex ? result[downIndex[1]] : result
			}
			return result
			// const _jsonFormat = function (json, index) {
			// 	const downIndex = arr[index].match(/\[([^\]]+)\]/)
			// 	const key = downIndex ? arr[index].replace(downIndex[0], '') : arr[index]
			// 	result = key ? json[key] : json
			// 	result = downIndex ? result[downIndex[1]] : result
			// 	if ( arr.length > index + 1 ) {
			// 		_jsonFormat(result, index+1)
			// 	} else {
			// 		resolve(result)
			// 	}
			// }
			// _jsonFormat(lastResult, 0)
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const selFormat = function (lastResult, rule) {
		try{
			let result = lastResult
			let arr = rule.split('>>')
			for ( let i =0; i < arr.length; i++ ) {
				const attrs = arr[i].split('.')
				const downIndex = attrs[1] ? attrs[1].match(/\[([^\]]+)\]/) : null
				result = Utils.typeof(result) == 'Array' ? result[0] : result
				const document = Utils.typeof(result) == 'String' ? new HTMLParser(result.trim()) : new HTMLParser(result.outerHTML.trim())
				if ( attrs[0] == 'class' ) {
					result = downIndex ? document.getElementsByClassName(attrs[1].replace(downIndex[0], '') )[downIndex[1]] : document.getElementsByClassName(attrs[1])
				} else if ( attrs[0] == 'id' ) {
					result = document.getElementById(attrs[1])
				} else if ( attrs[0] == 'tag' ) {
					result = downIndex ? document.getElementsByTagName(attrs[1].replace(downIndex[0], '') )[downIndex[1]] : document.getElementsByTagName(attrs[1])
				} else if ( attrs[0] == 'attr' ) {
					result = result.attributes[attrs[1]]
				} else if ( attrs[0] == 'html' ) {
					result = result.outerHTML.trim()
				} else if ( attrs[0] == 'content' ) {
					result = result.innerHTML.trim()
				} else if ( attrs[0] == 'text' ) {
					result = result.innerHTML.trim()
					result = result.replace(/<[^>]+>/g, '').trim()
				}
			}
			return result
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const forFormat = function (lastResult, rule) {
		try{
			let handle = eval("( function () { var result = []; lastResult.forEach((item, key) => {" + rule +  "}); return result } )")
			return handle()
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const mapFormat = function (lastResult, rule) {
		try{
			let handle = eval("( function () { return lastResult.map((item, key) =>" + rule +  ") } )")
			return handle()
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const filterFormat = function (lastResult, rule) {
		try{
			let handle = eval("( function () { return lastResult.filter((item, key) =>" + rule +  ") } )")
			return handle()
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const replaceFormat = function (lastResult, rule) {
		try{
			let arr = rule.split('>>')
			if ( arr.length > 0 ) {
				return lastResult.replace(arr[0], arr[1] || '')
			} else { return lastResult }
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const replaceAllFormat = function (lastResult, rule) {
		try{
			let arr = rule.split('>>')
			if ( arr.length > 0 ) {
				return lastResult.replace(eval(`/${arr[0]}/g`), arr[1] || '')
			} else { return lastResult }
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const splitFormat = function (lastResult, rule) {
		try{
			const arr = rule.split('>>')
			const split = arr[0]
			return arr[1] ? lastResult.split(split)[arr[1]] : lastResult.split(split)
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const findFormat = function (lastResult, rule) {
		try{
			let handle = eval("( function () { var index = lastResult.findIndex((item, key) =>" + rule +  "); return index > -1 ? lastResult[index] : '' } )")
			return handle()
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const sortFormat = function (lastResult, rule) {
		try{
			let handle = eval("( function () { lastResult.sort((a, b) =>" + rule +  "); return lastResult } )")
			return handle()
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const trimFormat = function (lastResult, rule) {
		try{
			return lastResult.trim()
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const haveFormat = function (lastResult, rule) {
		try{
			return lastResult.indexOf(rule) > -1
		}catch(e){
			throwerror(rule, e)
			return false
		}
	}
	
	const equalFormat = function (lastResult, rule) {
		try{
			return lastResult == rule
		}catch(e){
			throwerror(rule, e)
			return false
		}
	}
	
	const unequalFormat = function (lastResult, rule) {
		try{
			return lastResult != rule
		}catch(e){
			throwerror(rule, e)
			return false
		}
	}
	
	const evalFormat = function (lastResult, rule) {
		try{
			const handle = eval( "(" + lastResult + ")" )
			return typeof handle == "function" ? handle() : handle
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const matchFormat = function (lastResult, rule) {
		try{
			let arr = rule.split('>>')
			const match = lastResult.match(eval(`/${arr[0]}*([\\s\\S]*?)${arr[1]}/`) )
			return arr[2] && match ? match[arr[2]] : match
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const stringFormat = function (lastResult, rule) {
		try{
			let binary = rule || 10
			return lastResult.toString(binary)
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const dateFormatFormat = function (lastResult, rule) {
		try{
			let formats = rule || 'yyyy-mm-dd hh:mm:ss'
			return dateFormat(lastResult, formats)
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const joinFormat = function (lastResult, rule) {
		try{
			let binary = rule || ','
			return lastResult.join(binary)
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const reverseFormat = function (lastResult, rule) {
		try{
			return lastResult.reverse()
		}catch(e){
			throwerror(rule, e)
			return ''
		}
	}
	
	const throwerror = function (rule, e) {
		if ( network ) network.log += rule + '：' + e.toString() + '\n\n'
	}
	//生成请求
	const requestName = name || ''
	let response, baseUrl = req.source.href, network = {source: req.source.title, name: requestName, log: ''}
	const page = query.currentPage ? parseInt(query.currentPage) : ''
	const keyword = query.keyword || ''
	let detailUrl = query.detailUrl || ''
	let commentUrl = query.commentUrl || ''
	let lyricUrl = query.lyricUrl || ''
	let barrageUrl = query.barrageUrl || ''
	let contextUrl = query.contextUrl || ''
	let catalogUrl = query.catalogUrl || ''
	let characterUrl = query.characterUrl || ''
	let recomeUrl = query.recomeUrl || ''
	for ( let i = 0;i < 7;i++ ) {
		let nowUrl = i == 0 ? detailUrl : i == 1 ? commentUrl : i == 2 ? lyricUrl : i == 3 ? barrageUrl : i == 4 ? contextUrl : i == 5 ? catalogUrl : i == 6 ? characterUrl : i == 7 ? recomeUrl : ''
		if ( nowUrl  ) {
			const arr = extractPatternData(nowUrl, statement)
			arr.forEach(item => {
				if ( item.type == '@relation:' ) {
					nowUrl = nowUrl.replace(item.type + item.data, '')
					if ( i == 0 ) detailUrl = nowUrl
					else if ( i == 1 ) commentUrl = nowUrl
					else if ( i == 2 ) lyricUrl = nowUrl
					else if ( i == 3 ) barrageUrl = nowUrl
					else if ( i == 4 ) contextUrl = nowUrl
					else if ( i == 5 ) catalogUrl = nowUrl
					else if ( i == 6 ) characterUrl = nowUrl
					else if ( i == 7 ) recomeUrl = nowUrl
				}
			})
		}
	}
	//额外字段
	const extra = query.extra ? typeof query.extra == 'string' ? eval('( function () { return {' + query.extra + '}} )')() : query.extra : {}
	//自定义方法
	const Fnc = {}
	const fnc = req.source.fnc || {}
	Object.keys(fnc).forEach(key => {
		Fnc[key] = typeof fnc[key] == 'string' ? eval('(' + fnc[key] + ')') : eval('(' + fnc[key].toString() + ')' )
	})
	//请求资源
	const resource = {}
	Object.keys(query).forEach(key => {
		if ( key != 'currentPage' && key != 'keyword' && key != 'reqId' ) resource[key] = query[key]
	})
	//动态域名
	if ( req.source.dynamic ) {
		const baseRequestConfig = await urlFormat(baseUrl, req)
		const baseMethod = baseRequestConfig.method || 'get'
		const baseParams = baseRequestConfig.params || {}
		const baseHeader = baseRequestConfig.header || {}
		const baseRequestUrl = baseRequestConfig.url || baseUrl
		const newBaseUrl = await request[baseHeader.Charset == 'gbk' ? 'xhr' : 'http'][baseMethod](baseRequestUrl, {
			params: baseParams,
			mimeType: baseHeader.mimeType || (baseHeader.Charset == 'gbk' ? 'text/html;charset=gb2312' : undefined),
			header: Object.assign({}, {
				Referer: baseRequestUrl,
				'user-agent': req.ua || undefined,
			}, baseHeader)
		}).then(async res => {
			return await baseUrlFormat(typeof res.data == 'string' ? htmlDecode(res.data) : res.data, req.source.dynamic)
		}).catch(err => {
			return ''
		})
		baseUrl = newBaseUrl || baseUrl
		const baseRule = escapeFormat(baseUrl)
		const baseArr = extractPatternData(baseRule, statement)
		baseArr.forEach(item => {
			if ( item.type == '@type:' ) {
				baseRule = baseRule.replace('@type:' + item.data, '')
			}
			if ( item.type == '@method:' ) {
				baseRule = baseRule.replace('@method:' + item.data, '')
			}
			if ( item.type == '@header:' ) {
				baseRule = baseRule.replace('@header:' + value, '')
			}
			if ( item.type == '@params:' ) {
				baseRule = baseRule.replace('@params:' + value, '')
			}
			if ( item.type == '@relation:' ) {
				baseRule = baseRule.replace('@relation:' + item.data, '')
			}
		})
		baseUrl = baseRule
	}
	//网络请求
	const requestConfig = await urlFormat(url)
	const requestUrl = requestConfig.url ? requestConfig.url.slice(0, 4) == 'http' ? requestConfig.url : baseUrl + requestConfig.url : ''
	const method = requestConfig.method || 'get'
	const params = requestConfig.params || {}
	const header = requestConfig.header || {}
	const type = requestConfig.type || req.type || query.type || undefined
	network = Object.assign({}, network, { url: requestUrl, method, params, header, type })
	if ( lastDetailData && lastDetailUrl == requestUrl ) {
		network.response = lastDetailData
		return resultsFormat(lastDetailData, req)
	} else {
		return await request[header.Charset == 'gbk' ? 'xhr' : 'http'][method](requestUrl, {
			params: params,
			mimeType: header.mimeType || (header.Charset == 'gbk' ? 'text/html;charset=gb2312' : undefined),
			header: Object.assign({}, {
				Referer: baseUrl,
				'user-agent': req.ua || undefined,
			}, header)
		}).then(res => {
			network.response = res
			if ( requestName == 'detail' ) {
				lastDetailData = res
				lastDetailUrl = requestUrl
			}
			return resultsFormat(res, req)
		}).catch(err => {
			return { code: ERR_FALSE, data: null, network }
		})
	}
}

//转义html特殊字符
function htmlDecode (str) {
	let s = ""
	if (str.length == 0) return ""
	// s = str.replace(/&#x/g, "\\u")
	s = str.replace(/&#58;/g, ":")
	s = s.replace(/&#32;/g, " ")
	s = s.replace(/&#33;/g, "!")
	s = s.replace(/&#34;/g, '"')
	s = s.replace(/&#35;/g, "#")
	s = s.replace(/&#36;/g, "$")
	s = s.replace(/&#37;/g, "%")
	s = s.replace(/&#38;/g, "&")
	s = s.replace(/&#39;/g, "'")
	s = s.replace(/&#40;/g, "(")
	s = s.replace(/&#41;/g, ")")
	s = s.replace(/&#42;/g, "*")
	s = s.replace(/&#43;/g, "+")
	s = s.replace(/&#44;/g, ",")
	s = s.replace(/&#45;/g, "-")
	s = s.replace(/&#46;/g, ".")
	s = s.replace(/&#47;/g, "/")
	s = s.replace(/&#13;/g, "\n")
	s = s.replace(/<br\/>/g, "\n")
	s = s.replace(/<br \/>/g, "\n")
	s = s.replace(/<br>/g, "\n")
	s = s.replace(/&amp;/g, "")
	s = s.replace(/&nbsp;/g, " ")
	s = s.replace(/&#8211;/g, "–")
	s = s.replace(/#65279;/g, "")
	s = s.replace(/&hellip;/g, '...')
	s = s.replace(/&mdash;/g, '—')
	s = s.replace(/&ldquo;/g, "“")
	s = s.replace(/&rdquo;/g, "”")
	s = s.replace(/&middot;/g, ".")
	s = s.replace(/&iexcl;/g, "¡")
	s = s.replace(/&cent;/g, "¢")
	s = s.replace(/&pound;/g, "£")
	s = s.replace(/&curren;/g, "¤")
	s = s.replace(/&yen;/g, "¥")
	s = s.replace(/&sect;/g, "§")
	s = s.replace(/&uml;/g, "¨")
	s = s.replace(/&copy;/g, "©")
	s = s.replace(/&ordf;/g, "ª")
	s = s.replace(/&laquo;/g, "«")
	s = s.replace(/&not;/g, "¬")
	s = s.replace(/&reg;/g, "®")
	s = s.replace(/&macr;/g, "¯")
	s = s.replace(/&deg;/g, "°")
	s = s.replace(/&plusmn;/g, "±")
	s = s.replace(/&acute;/g, "´")
	s = s.replace(/&micro;/g, "µ")
	s = s.replace(/&para;/g, "¶")
	s = s.replace(/&middot;/g, "·")
	s = s.replace(/&cedil;/g, "¸")
	s = s.replace(/&ordm;/g, "º")
	s = s.replace(/&raquo;/g, "»")
	s = s.replace(/&iquest;/g, "¿")
	s = s.replace(/&Agrave;/g, "À")
	s = s.replace(/&Aacute;/g, "Á")
	s = s.replace(/&Acirc;/g, "Â")
	s = s.replace(/&Atilde;/g, "Ã")
	s = s.replace(/&Auml;/g, "Ä")
	s = s.replace(/&Aring;/g, "Å")
	s = s.replace(/&AElig;/g, "Æ")
	s = s.replace(/&Ccedil;/g, 'Ç')
	s = s.replace(/&Egrave;/g, "È")
	s = s.replace(/&Eacute;/g, "É")
	s = s.replace(/&Ecirc;/g, "Ê")
	s = s.replace(/&Euml;/g, "Ë")
	s = s.replace(/&Igrave;/g, "Ì")
	s = s.replace(/&Iacute;/g, "Í")
	s = s.replace(/&Icirc;/g, "Î")
	s = s.replace(/&Iuml;/g, "Ï")
	s = s.replace(/&Ntilde;/g, "Ñ")
	s = s.replace(/&Ograve;/g, "Ò")
	s = s.replace(/&Oacute;/g, "Ó")
	s = s.replace(/&Ocirc;/g, "Ô")
	s = s.replace(/&Otilde;/g, "Õ")
	s = s.replace(/&Ouml;/g, "Ö")
	s = s.replace(/&Oslash;/g, "Ø")
	s = s.replace(/&Ugrave;/g, "Ù")
	s = s.replace(/&Uacute;/g, "Ú")
	s = s.replace(/&Ucirc;/g, "Û")
	s = s.replace(/&Uuml;/g, "Ü")
	s = s.replace(/&szlig;/g, "ß")
	s = s.replace(/&agrave;/g, "à")
	s = s.replace(/&aacute;/g, "á")
	s = s.replace(/&acirc;/g, "â")
	s = s.replace(/&atilde;/g, "ã")
	s = s.replace(/&auml;/g, "ä")
	s = s.replace(/&aring;/g, "å")
	s = s.replace(/&aelig;/g, "æ")
	s = s.replace(/&ccedil;/g, "ç")
	s = s.replace(/&egrave;/g, "è")
	s = s.replace(/&eacute;/g, "é")
	s = s.replace(/&ecirc;/g, "ê")
	s = s.replace(/&euml;/g, "ë")
	s = s.replace(/&igrave;/g, "ì")
	s = s.replace(/&iacute;/g, "í")
	s = s.replace(/&icirc;/g, "î")
	s = s.replace(/&iuml;/g, "ï")
	s = s.replace(/&ntilde;/g, "ñ")
	s = s.replace(/&ograve;/g, "ò")
	s = s.replace(/&oacute;/g, "ó")
	s = s.replace(/&ocirc;/g, "ô")
	s = s.replace(/&otilde;/g, "õ")
	s = s.replace(/&ouml;/g, "ö")
	s = s.replace(/&divide;/g, "÷")
	s = s.replace(/&oslash;/g, "ø")
	s = s.replace(/&ugrave;/g, "ù")
	s = s.replace(/&uacute;/g, "ú")
	s = s.replace(/&ucirc;/g, "û")
	s = s.replace(/&uuml;/g, "ü")
	s = s.replace(/&yuml;/g, "ÿ")
	return s
}

function getTag (params) {
	let cc = (params.title || '') + '_' + (params.creator || '') + '_' + (params.style || '') + '_' + (params.desc || '')
	return [...new Set((params.tag || '').split(',').concat(trie.splitWords(cc)))].filter(t => t).toString()
}

export function escapeFormat (str) {
	str = str.replace(/&es;/g, '\\')
	str = str.replace(/&wrap;/g, '\n')
	str = str.replace(/&nbsp;/g, ' ')
	str = str.replace(/&tabu;/g, '\t')
	str = str.replace(/&quot;/g, '\"')
	str = str.replace(/&apos;/g, "\'")
	str = str.replace(/&lt;/g, "<")
	str = str.replace(/&gt;/g, ">")
	str = str.replace(/&oe;/g, "{")
	str = str.replace(/&ce;/g, "}")
	return str
}

export function extractPattern (inputString, patterns) {
	const extractedData = [];
	const patternsSync = inputString.match(eval(`/${patterns.join('|')}/g`)) || []
	patternsSync.forEach((pattern, key) => {
		let matches
	    const regex = new RegExp(`(${pattern})([\\s\\S]*?)(${patterns.join('|')}|$)`);
		const match = regex.exec(inputString)
		if ( match ) {
			matches = { type: match[1], data: match[2] }
			extractedData.push(matches);
			inputString = inputString.replace(matches.type + matches.data, '')
		}
	});
	return extractedData
}

export async function getClassification (req, rule) {
	const list = []
	const arr = rule.split('$:')
	for ( let i = 0; i < arr.length; i++ ) {
		const item = arr[i]
		let child = []
		const title = item.split('?:').length > 1 ? item.split('?:')[0] : ''
		const urlRule = item.split('?:').length > 1 ? item.split('?:')[1] : item
		const preIndex = urlRule.indexOf(':')
		const pre = urlRule.slice(0, preIndex+1)
		if ( pre == '@sync:' ) {
			try{
				const handle = eval('( function () {' + escapeFormat(urlRule.replace(pre, '')) + '} )')
				child = handle() || []
			}catch(e){
				child = []
				uni.showToast({
					title: e.toString(),
					icon:'none',
					duration: 5000
				})
			}
		} else if ( pre == '@async:' ) {
			try{
				const handle = eval('( async function () {' + escapeFormat(urlRule.replace(pre, '')) + '} )')
				child = await handle() || []
			}catch(e){
				child = []
				uni.showToast({
					title: e.toString(),
					icon:'none',
					duration: 5000
				})
			}
		} else {
			let urls = urlRule.split('+:')
			urls.forEach(url => {
				child.push({
					label: url.split('::')[0],
					value: url.split('::')[1]
				})
			})
		}
		list.push({
			title: title,
			child,
			req: req
		})
	}
	return list
}